#pragma once

#include "../mqcommon/msg.pb.h"
#include "../mqcommon/helper.hpp"
#include "../mqcommon/log.hpp"

namespace mymq
{
    class Router
    {
    public:
        static bool IsLegalRoutingKey(const std::string& routing_key)
        {
            // 判断合法字符a~z、A~Z、.、_、0~9
            for (const auto& ch: routing_key)
            {
                if ((ch >= 'a' && ch <= 'z') || 
                    (ch >= 'A' && ch <= 'Z') || 
                    (ch >= '0' && ch <= '9') || 
                    (ch == '.' || ch == '_'))
                {
                    continue;
                }
                return false;
            }
            return true;
        }
        static bool IsLegalBindingKey(const std::string& binding_key)
        {
            // 1.判断合法字符a~z、A~Z、.、_、0~9、*、#
            for (const auto& ch: binding_key)
            {
                if ((ch >= 'a' && ch <= 'z') || 
                    (ch >= 'A' && ch <= 'Z') || 
                    (ch >= '0' && ch <= '9') || 
                    (ch == '.' || ch == '_') || 
                    (ch == '*' || ch == '#'))
                {
                    continue;
                }
                return false;
            }
            // 2.*和#必须独立出现
            std::vector<std::string> sub_str;
            StrHelper::Split(binding_key, ".", &sub_str);
            for (const auto& str: sub_str)
            {
                if (str.size() != 1 && 
                    (str.find(".") != std::string::npos || str.find("#") != std::string::npos))
                {
                    return false;
                }
            }
            // 3.*和#的相邻问题
            for (size_t i = 1; i < sub_str.size(); i++)
            {
                if (sub_str[i] == "#" && sub_str[i - 1] == "#")
                    return false;
                if (sub_str[i] == "*" && sub_str[i - 1] == "#")
                    return false;
                if (sub_str[i] == "#" && sub_str[i - 1] == "*")
                    return false;
            }
            return true;
        }
        static bool Route(ExchangeType type, const std::string& binding_key, const std::string& routing_key)
        {
            if (type == ExchangeType::DIRECT)
            {
                return routing_key == binding_key;
            }
            else if (type == ExchangeType::FUNOUT)
                return true;
            else if (type == ExchangeType::TOPIC)
            {
                // 规则匹配
                // 1.将binding_key与routing_key进行字符串分割，得到各个单词的数组
                std::vector<std::string> bkeys, rkeys;
                size_t n_bkey = StrHelper::Split(binding_key, ".", &bkeys);
                size_t n_rkey = StrHelper::Split(routing_key, ".", &rkeys);
                //bkeys的起始不是通配符的情况下，起始单词不同，则直接返回 false，匹配失败
                if (bkeys[0] != "*" && bkeys[0] != "#" && bkeys[0] != rkeys[0])
                {
                    return false;
                } 
                // 2.定义标记数组，并初始化dp[0][0]为1
                std::vector<std::vector<int>> dp(n_bkey + 1, std::vector<int>(n_rkey + 1));
                dp[0][0] = 1;
                // 3.如果binding_key以#起始，则将对应行的第0列置为1
                for (int i = 1; i <= n_bkey; i++)
                {
                    if (bkeys[i - 1] == "#")
                    {
                        dp[i][0] = 1;
                        continue;
                    }
                    break;
                }
                // 4.使用routing_key中的每个单词与binding_key中的每个单词进行匹配并标记数组
                for (int i = 1; i <= n_bkey; i++)
                {
                    for (int j = 1; j <= n_rkey; j++)
                    {
                        // 如果单词匹配，则从左上方继承结果
                        if (bkeys[i - 1] == rkeys[j - 1] || bkeys[i - 1] == "*")
                            dp[i][j] = dp[i - 1][j - 1];
                        // 如果bkey是个#，则需从左上、左边、上边继承结果
                        else if (bkeys[i - 1] == "#")
                            dp[i][j] = dp[i - 1][j - 1] || dp[i][j - 1] || dp[i - 1][j];
                    }
                }
                return dp[n_bkey][n_rkey];
            }
            else // 类型为UNKONW
            {
                INFO_LOG("交换机类型为UNKONW，没有路由规则");
                return false;
            }
        }
    };
}